package yushuman.rbac.dao.file;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import yushuman.rbac.domain.entity.BaseEntity;
import yushuman.rbac.exception.FatalException;
import yushuman.rbac.exception.PersistenceException;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 持久化工具类-读写对象
 *
 * @author 俞舒熳
 * @since 2025/6/7 15:13
 */
public class PersistUtil {

    private static final Logger logger = LoggerFactory.getLogger(PersistUtil.class);

    // 数据文件存储路径
    private static final Path rootPath = Paths.get("./data");

    private static final Map<Class<? extends BaseEntity>, Path> dirMap = new HashMap<>();

    private static <T extends BaseEntity> Path getDir(Class<T> clazz) {
        if (!dirMap.containsKey(clazz)) {
            Path dir = rootPath.resolve(clazz.getSimpleName().toLowerCase());
            try {
                Files.createDirectories(dir);
                dirMap.put(clazz, dir);
            } catch (IOException e) {
                logger.error("创建数据存储目录失败：", e);
                throw new FatalException();
            }
        }
        return dirMap.get(clazz);
    }

    public static <T extends BaseEntity> boolean exists(Class<T> clazz, Integer id) {
        Path dir = getDir(clazz);
        Path file = dir.resolve(id.toString());
        return Files.exists(file);
    }

    public static <T extends BaseEntity> void write(T obj) {
        Path file = getDir(obj.getClass()).resolve(obj.getId().toString());
        try (ObjectOutputStream dos = new ObjectOutputStream(Files.newOutputStream(file))) {
            dos.writeObject(obj);
        } catch (IOException e) {
            logger.error("创建文件失败，数据类型：{}, ID：{}", obj.getClass().getSimpleName(), obj.getId(), e);
            throw new PersistenceException(e);
        }
    }

    public static <T extends BaseEntity> T read(Class<T> clazz, Integer id) {
        Path file = getDir(clazz).resolve(id.toString());
        try (ObjectInputStream dos = new ObjectInputStream(Files.newInputStream(file))) {
            return clazz.cast(dos.readObject());
        } catch (IOException | ClassNotFoundException e) {
            logger.error("读取数据文件失败，数据类型：{}，ID：{}", clazz.getSimpleName(), id, e);
            throw new PersistenceException(e);
        }
    }

    public static <T extends BaseEntity> void delete(Class<T> clazz, Integer id) {
        Path file = getDir(clazz).resolve(id.toString());
        try {
            Files.delete(file);
        } catch (IOException e) {
            logger.error("删除文件失败，数据类型：{}，ID：{}", clazz.getSimpleName(), id, e);
            throw new PersistenceException(e);
        }
    }

    public static <T extends BaseEntity> List<T> readAll(Class<T> clazz) {
        Path dir = getDir(clazz);
        List<T> list = new ArrayList<>();
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
            for (Path entry : stream) {
                Integer id = Integer.parseInt(entry.getFileName().toString());
                list.add(read(clazz, id));
            }
            return list;
        } catch (IOException e) {
            logger.error("读取数据文件列表失败，数据类型：{}", clazz.getSimpleName(), e);
            throw new PersistenceException(e);
        }
    }

    public static <T extends BaseEntity> List<String> listFileNames(Class<T> clazz) {
        Path dir = getDir(clazz);
        List<String> list = new ArrayList<>();
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
//            for(Path entry: stream) {
//                String fileName = entry.getFileName().toString();
//                list.add(fileName);
//            }
            stream.forEach(path -> list.add(path.getFileName().toString()));
            return list;
        } catch (IOException e) {
            logger.error("读取数据文件列表失败，数据类型：{}", clazz.getSimpleName(), e);
            throw new PersistenceException(e);
        }
    }
}

